#include "MeshDemo.h"
#include "Camera.h"
#include "RenderManager.h"

struct ConstMeshBuffer
{
	XMMATRIX m_world;
	XMMATRIX m_view;
	XMMATRIX m_proj;
};

MeshDemo::MeshDemo()
{
}


MeshDemo::~MeshDemo()
{
}

struct IndexData
{
	int VIndex;
	int UVIndex;
	int NIndex;
};
bool MeshDemo::LoadContent()
{
	if (!LoadMesh())
	{
		return false;
	}
	ID3DBlob *vsBuffer = 0;
	bool compileResult = CompileD3DShader(L"ShaderMesh.fx", "VS_Main", "vs_4_0", &vsBuffer);
	if (!compileResult)
	{
		MessageBox(0, L"载入顶点着色器错误", L"编译错误", MB_OK);
		return false;
	}

	HRESULT result;
	result = RenderManager::GetRenderManagerInstance()->GetD3DDeviece()->CreateVertexShader(vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(),
		0, &m_pSolidColorVS);

	if (FAILED(result))
	{
		if (vsBuffer)
		{
			vsBuffer->Release();
		}
		return false;
	}

	D3D11_INPUT_ELEMENT_DESC solidColorLayout[] =
	{
		{ "POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },
		{ "TEXCOORD",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0 },
	};

	UINT numLayoutElements = ARRAYSIZE(solidColorLayout);
	result = RenderManager::GetRenderManagerInstance()->GetD3DDeviece()->CreateInputLayout(solidColorLayout, numLayoutElements, vsBuffer->GetBufferPointer(),
		vsBuffer->GetBufferSize(), &m_pInputLayout);
	vsBuffer->Release();

	if (FAILED(result))
	{
		return false;
	}

	//载入像素着色器
	ID3DBlob *psBuffer = 0;
	compileResult = CompileD3DShader(L"ShaderMesh.fx", "PS_Main", "ps_4_0", &psBuffer);
	if (!compileResult)
	{
		MessageBox(0, L"像素着色器加载失败",L"编译错误", MB_OK);
		return false;
	}

	result = RenderManager::GetRenderManagerInstance()->GetD3DDeviece()->CreatePixelShader(psBuffer->GetBufferPointer(), psBuffer->GetBufferSize(),
		0, &m_pSolidColorPS);
	psBuffer->Release();
	if (FAILED(result))
	{
		return false;
	}


	//构造顶点
	D3D11_BUFFER_DESC vertexDesc;
	ZeroMemory(&vertexDesc, sizeof(vertexDesc));
	vertexDesc.Usage = D3D11_USAGE_DEFAULT;
	vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexDesc.ByteWidth = sizeof(VertexMesh) * MyMesh.vertexBuff.size();

	D3D11_SUBRESOURCE_DATA resourceData;
	ZeroMemory(&resourceData, sizeof(resourceData));
	resourceData.pSysMem = MyMesh.vertexBuff.data();

	result = RenderManager::GetRenderManagerInstance()->GetD3DDeviece()->CreateBuffer(&vertexDesc, &resourceData, &m_pVertexBuffer);
	if (FAILED(result))
	{
		return false;
	}

	//D3D11_BUFFER_DESC vertexIndexDesc;
	//ZeroMemory(&vertexIndexDesc, sizeof(vertexIndexDesc));
	//vertexIndexDesc.Usage = D3D11_USAGE_DEFAULT;
	//vertexIndexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	//vertexIndexDesc.ByteWidth = sizeof(WORD) * MyMesh.IndexBuff.size();
	//vertexIndexDesc.CPUAccessFlags = 0;

	//D3D11_SUBRESOURCE_DATA IndexData;
	//ZeroMemory(&IndexData, sizeof(IndexData));
	//IndexData.pSysMem = MyMesh.IndexBuff.data();
	//result = m_pd3dDevice->CreateBuffer(&vertexIndexDesc, &IndexData, &m_pIndexBuffer);
	//if (FAILED(result))
	//{
	//	return false;
	//}



	D3D11_BUFFER_DESC cbDesc;
	ZeroMemory(&cbDesc, sizeof(D3D11_BUFFER_DESC));
	cbDesc.ByteWidth = sizeof(ConstMeshBuffer);
	cbDesc.Usage = D3D11_USAGE_DEFAULT;
	cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	cbDesc.CPUAccessFlags = 0;

	result = RenderManager::GetRenderManagerInstance()->GetD3DDeviece()->CreateBuffer(&cbDesc, nullptr,
		&g_pConstantBuffer11);
	if (FAILED(result))
	{
		MessageBoxA(0, 0, 0, 0);
		return false;
	}

	//贴图
	result = DXUTCreateShaderResourceViewFromFile(RenderManager::GetRenderManagerInstance()->GetD3DDeviece(), L"Orc Skin (Diffuse).png", &g_pTextureRV);
	if (FAILED(result))
		return false;

	// Create the sample state
	D3D11_SAMPLER_DESC sampDesc;
	ZeroMemory(&sampDesc, sizeof(sampDesc));
	sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	sampDesc.MinLOD = 0;
	sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
	result = RenderManager::GetRenderManagerInstance()->GetD3DDeviece()->CreateSamplerState(&sampDesc, &g_pSamplerLinear);
	if (FAILED(result))
		return false;

	//构建矩阵
	XMFLOAT4 TransFrom(0.f,0.f,0.f,1.f);
	TransFrom.x = Pos.x;
	TransFrom.y = Pos.y;
	TransFrom.z = Pos.z;
	g_MeshWorld = XMMatrixRotationX(Rotation.x/180* XM_PI)*XMMatrixRotationY(Rotation.y / 180 * XM_PI)*XMMatrixRotationY(Rotation.z / 180 * XM_PI)
				 *XMMatrixTranslationFromVector(XMLoadFloat4(&TransFrom));

	//g_MeshView = XMMatrixLookAtLH(Eye, At, Up);
	//g_MeshProjection = XMMatrixPerspectiveFovLH(XM_PIDIV2 / 6, 1024.f / 768.f, 0.01f, 200.0f);

	return true;
}

void MeshDemo::UnLoadContent()
{
	if (m_pSolidColorPS)
		m_pSolidColorPS->Release();
	if (m_pSolidColorVS)
		m_pSolidColorVS->Release();
	if (m_pVertexBuffer)
		m_pVertexBuffer->Release();
	if (m_pInputLayout)
		m_pInputLayout->Release();
	if (g_pConstantBuffer11)
		g_pConstantBuffer11->Release();
	if (m_pIndexBuffer)
		m_pIndexBuffer->Release();

	m_pSolidColorVS = 0;
	m_pSolidColorPS = 0;
	m_pVertexBuffer = 0;
	m_pInputLayout = 0;
	m_pIndexBuffer = nullptr;
	g_pConstantBuffer11 = nullptr;
	
}

void MeshDemo::Update(float dt)
{
	static float t = 0.0f;
	static ULONGLONG timeStart = 0;
	ULONGLONG timeCur = GetTickCount64();
	if (timeStart == 0)
		timeStart = timeCur;
	t = (timeCur - timeStart) / 1000.f;
	Rotation.y += 0.01;
	// Rotate cube around the origin
	XMFLOAT4 TransFrom(0.f, 0.f, 0.f, 1.f);
	TransFrom.x = Pos.x;
	TransFrom.y = Pos.y;
	TransFrom.z = Pos.z;
	g_MeshWorld = XMMatrixScaling(0.3, 0.3, 0.3)*XMMatrixRotationX(Rotation.x / 180 * XM_PI)*XMMatrixRotationY(Rotation.y / 180 * XM_PI)*XMMatrixRotationY(Rotation.z / 180 * XM_PI)
		*XMMatrixTranslationFromVector(XMLoadFloat4(&TransFrom));
	//g_MeshWorld = XMMatrixScaling(0.3, 0.3, 0.3)*XMMatrixRotationY(t / 2); //*XMMatrixRotationX(-XM_PIDIV2)
}

void MeshDemo::Render()
{
	if (RenderManager::GetRenderManagerInstance()->GetImmediateContext() == 0)
		return;
	if (TheCamera == nullptr)
	{
		return;
	}
	RenderManager::GetRenderManagerInstance()->SetNoCull(false);

	UINT stride = sizeof(VertexMesh);
	UINT offset = 0;
	//设置数据信息格式控制信息
	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->IASetInputLayout(m_pInputLayout);
	//设置要绘制的几何体信息
	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &stride, &offset);

	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
	//指明如何绘制三角形
	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->VSSetConstantBuffers(0, 1, &g_pConstantBuffer11);

	ConstMeshBuffer ConstBufferData;
	ConstBufferData.m_world = XMMatrixTranspose(g_MeshWorld);
	if (TheCamera)
	{
		ConstBufferData.m_view = XMMatrixTranspose(TheCamera->GetView());
		ConstBufferData.m_proj = XMMatrixTranspose(TheCamera->GetProj());
	}

	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->UpdateSubresource(
		g_pConstantBuffer11,
		0,
		nullptr,
		&ConstBufferData,
		0,
		0
		);

	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->VSSetShader(m_pSolidColorVS, 0, 0);
	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->PSSetShader(m_pSolidColorPS, 0, 0);
	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->GSSetConstantBuffers(0, 1, &g_pConstantBuffer11);
	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->PSSetShaderResources(0, 1, &g_pTextureRV);
	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->PSSetSamplers(0, 1, &g_pSamplerLinear);
	RenderManager::GetRenderManagerInstance()->GetImmediateContext()->Draw(MyMesh.vertexBuff.size(),0);

}
std::vector<string> MeshDemo::split(string str, string pattern)
{
	vector<string> ret;
	string result;
	stringstream input(pattern);
	while (input >> result)
		ret.push_back(result);
	return ret;
}

std::vector<std::string> MeshDemo::splitByStr(char str, string pattern)
{
	vector<string> ret;
	string result;
	stringstream input(pattern);
	while (getline(input, result,str))
		ret.push_back(result);
	return ret;
}

bool MeshDemo::isEqule(const VertexMesh& a, const VertexMesh& b)
{
	if (a.pos.x == b.pos.x && a.pos.y == b.pos.y && a.pos.z == b.pos.z && a.UV.x == b.UV.x && a.UV.y == b.UV.y)
	{
		if (a.normoal.x == b.normoal.x && a.normoal.y == b.normoal.y && a.normoal.z == b.normoal.z)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	return false;
}


bool MeshDemo::LoadMesh()
{
	fstream fin("FBX3.obj");  //打开文件
	string ReadLine;
	vector<XMFLOAT3> VPoss;
	vector<XMFLOAT2> TUVs;
	vector<XMFLOAT3> Normals;
	vector<IndexData> wIndex;
	while (getline(fin, ReadLine))  //逐行读取，直到结束
	{
		if (ReadLine != "")
		{
			vector<string> result = split(" ", ReadLine);
			if (result.size() > 0)
			{
				if (result[0] == "v")
				{
					if (result.size() > 3)
					{
						XMFLOAT3 pos;
						pos.x = (float)atof(result[1].c_str());
						pos.y = (float)atof(result[2].c_str());
						pos.z = -(float)atof(result[3].c_str());
						VPoss.push_back(pos);
					}

				}
				else if (result[0] == "vt")
				{
					if (result.size() > 2)
					{
						XMFLOAT2 uv;
						uv.x = (float)atof(result[1].c_str());
						uv.y = 1-(float)atof(result[2].c_str());
						TUVs.push_back(uv);
					}
				}
				else if (result[0] == "vn")
				{
					if (result.size() > 3)
					{
						XMFLOAT3 normal;
						normal.x = (float)atof(result[1].c_str());
						normal.y = (float)atof(result[2].c_str());
						normal.z = (float)atof(result[3].c_str());
						Normals.push_back(normal);
					}
				}
				else if (result[0] == "f")
				{
					if (result.size() > 3)
					{

						for (int j = 1; j <4 ; ++j)
						{
							vector<string> index;
							index = splitByStr('/', result[j]);
							if (index.size() >= 3)
							{
								IndexData Index;
								Index.VIndex = (atoi(index[0].c_str()) - 1);
								Index.UVIndex = (atoi(index[1].c_str()) - 1);
								Index.NIndex = (atoi(index[2].c_str()) - 1);
								wIndex.push_back(Index);
							}
						}				
					}
				}
			}
		}
	}
	//if (VPoss.size() != TUVs.size() || VPoss.size() ==0 || TUVs.size() == 0)
	//{
	//	return false;
	//}
	for (int i = 0; i < wIndex.size(); i++)
	{
		VertexMesh Vertex;
		Vertex.pos = VPoss[wIndex[i].VIndex];
		Vertex.UV = TUVs[wIndex[i].UVIndex];
		Vertex.normoal = Normals[wIndex[i].NIndex];
		//bool bFind = false;
		//for (int j = 0; j < MyMesh.vertexBuff.size(); j++)
		//{
		//	if (isEqule(MyMesh.vertexBuff[j], Vertex))
		//	{
		//		bFind = true;
		//		break;
		//	}
		//}
		//if (!bFind)
		//{
			MyMesh.vertexBuff.push_back(Vertex);
		//}
	}
	//vector<int> vindex;
	//bool a = false;
	//for (int i = 0; i < wIndex.size(); i++)
	//{
	//
	//	int index = -1;
	//	VertexMesh Vertex;
	//	Vertex.pos = VPoss[wIndex[i].VIndex];
	//	Vertex.UV = TUVs[wIndex[i].UVIndex];
	//	Vertex.normoal = Normals[wIndex[i].NIndex];
	//	for (int j = 0; j < MyMesh.vertexBuff.size(); j++)
	//	{
	//		if (isEqule(MyMesh.vertexBuff[j], Vertex))
	//		{
	//			index = j;
	//			break;
	//		}
	//	}
	//	if (index != -1)
	//	{
	//		vindex.push_back(index);
	//		if (vindex.size() == 3)
	//		{
	//			if (!a)
	//			{
	//				MyMesh.IndexBuff.push_back(vindex[0]);
	//				MyMesh.IndexBuff.push_back(vindex[1]);
	//				MyMesh.IndexBuff.push_back(vindex[2]);
	//			}
	//			else
	//			{
	//				MyMesh.IndexBuff.push_back(vindex[0]);
	//				MyMesh.IndexBuff.push_back(vindex[2]);
	//				MyMesh.IndexBuff.push_back(vindex[1]);
	//			}
	//			//a = !a;
	//			vindex.clear();
	//		}

	//		
	//	}
	//	else
	//	{
	//		int a = 0;
	//	}
	//}
	fin.close();
	return true;
}

